/*
*********************************************************************************************************
*
*	模块名称 : BSP DMA
*
*********************************************************************************************************
*/

#ifndef _BSP_DMA_H_
#define _BSP_DMA_H_

#ifdef __cplusplus
extern "C"
{
#endif

#include "stdint.h"
#include "bsp.h"

	/*******************************************************************************
	 * @brief  APP DMA type
	 *******************************************************************************/
	typedef struct
	{
		DMA_T *DMAx;						// DMA 模块
		DMA_Stream_T *stream;			    // DMA 数据流
		uint16_t ch_num;					// DMA 通道编号
		uint16_t trig_src; 					// DMA 触发源
		IRQn_Type irqn;						// 中断号
	} app_dma_type;

#ifdef IN_DMA_MOUDLE
#define dma_stream_make(name, dmax, ch, src) \
	const app_dma_type name = {              \
		.DMAx = dmax,                        \
		.stream = dmax##_Stream##ch,       \
		.ch_num = ch,                        \
		.trig_src = src,                     \
		.irqn = dmax##_STR##ch##_IRQn}
#else
#define dma_stream_make(name, dmax, ch, src) \
	extern const app_dma_type name
#endif

	/*******************************************************************************
	 * @brief  APP DMA CONFIG
	 *******************************************************************************/
	dma_stream_make(DMA_U01_RX, DMA2, 2, 4);
	dma_stream_make(DMA_U01_TX, DMA2, 7, 4);

	dma_stream_make(DMA_U04_RX, DMA1, 2, 4);
	dma_stream_make(DMA_U04_TX, DMA1, 4, 4);

	dma_stream_make(DMA_U06_RX, DMA2, 1, 5);
	dma_stream_make(DMA_U06_TX, DMA2, 6, 5);
	
	dma_stream_make(DMA_ADC, DMA2, 0, 0);

	/*******************************************************************************
	 * @brief  中断回调注册
	 *******************************************************************************/
	typedef struct
	{
		void (*stream10)(void);
		void (*stream11)(void);
		void (*stream12)(void);
		void (*stream13)(void);
		void (*stream14)(void);
		void (*stream15)(void);
		void (*stream16)(void);
		void (*stream17)(void);
		void (*stream20)(void);
		void (*stream21)(void);
		void (*stream22)(void);
		void (*stream23)(void);
		void (*stream24)(void);
		void (*stream25)(void);
		void (*stream26)(void);
		void (*stream27)(void);
	} dma_it_type;

	extern dma_it_type dma_it;

	/*******************************************************************************
	 * @brief  APP DMA API
	 *******************************************************************************/
	void dma_nvic_set(const app_dma_type *dmax, uint32_t irq_en, void (*callback)(void));

	/*******************************************************************************
	 * @brief  配置
	 *******************************************************************************/
	typedef struct
	{
		uint8_t mem_to_periph;
		uint8_t cycle_mode;
		uint8_t mem_inc, periph_inc;
		uint16_t data_len;
		DMA_PRIORITY_T prio;
		void *mem;
		volatile void *periph;
	} dma_stream_cfg_type;

	void dma_stream_config(const app_dma_type *dmax, dma_stream_cfg_type *cfg);
	/*******************************************************************************
	 * @brief  获取传输完成标志
	 * \param[in] dma
	 * \retval:  0-No 1-Yes
	 *******************************************************************************/
	__STATIC_INLINE uint32_t dma_comp_flag_get(const app_dma_type *dmax)
	{
		int ch_num = dmax->ch_num;
		uint32_t bit_pos = ((ch_num % 4) / 2) * 16 + (ch_num % 2) * 6 + 5;

		return ((&(dmax->DMAx->LINTSTS))[ch_num / 4] >> bit_pos) & 1;
	}

	/*******************************************************************************
	 * @brief  清除传输完成标志
	 * \param[in] dma
	 * \retval:  0-No 1-Yes
	 *******************************************************************************/
	__STATIC_INLINE void dma_comp_flag_clr(const app_dma_type *dmax)
	{
		int ch_num = dmax->ch_num;
		uint32_t bit_pos = ((ch_num % 4) / 2) * 16 + (ch_num % 2) * 6 + 5;

		(&(dmax->DMAx->LIFCLR))[ch_num / 4] = 0x3DUL << bit_pos;
	}

/*******************************************************************************
 * @brief  库接口映射
 * \param[in] dma
 * \retval:  0-No 1-Yes
 *******************************************************************************/
/* 反初始化 */
#define dma_stream_deinit(dmax) DMA_Reset((dmax)->stream)

/* 判断是否已使能DMA数据流 */
#define is_dma_stream_enable(dmax) (dmax)->stream->SCFG_B.EN

/* 使能DMA数据流 */
#define dma_stream_enable(dmax) \
	dma_comp_flag_clr(dmax);    \
	DMA_Enable((dmax)->stream)

/* 禁能DMA数据流 */
#define dma_stream_disable(dmax) DMA_Disable((dmax)->stream)

/* 设置DMA数据流RAM地址 */
#define dma_stream_set_mem_addr(dmax, addr) (dmax)->stream->M0ADDR = (addr)

/* 设置DMA数据流外设地址 */
#define dma_stream_set_periph_addr(dmax, addr) (dmax)->stream->PADDR = (addr)

/* 设置DMA数据流数据长度 */
#define dma_stream_set_data_len(dmax, len) (dmax)->stream->NDATA = (len)

/* 获取DMA数据流剩余传输长度 */
#define dma_stream_get_data_len(dmax) (dmax)->stream->NDATA

/* 使能数据流传输完成中断 */
#define dma_stream_complete_isr_enable(dmax) (dmax)->stream->SCFG_B.TXCIEN = 1

#ifdef __cplusplus
}
#endif

#endif
